package com.loper7.date_time_picker.controller

import android.util.Log
import com.loper7.date_time_picker.DateTimeConfig
import com.loper7.date_time_picker.DateTimeConfig.DAY
import com.loper7.date_time_picker.DateTimeConfig.HOUR
import com.loper7.date_time_picker.DateTimeConfig.MIN
import com.loper7.date_time_picker.DateTimeConfig.MONTH
import com.loper7.date_time_picker.DateTimeConfig.SECOND
import com.loper7.date_time_picker.DateTimeConfig.YEAR
import com.loper7.date_time_picker.number_picker.NumberPicker
import java.text.SimpleDateFormat
import java.util.*

/**
 *
 * @CreateDate:     2020/9/11 13:36
 * @Description:    日期/时间逻辑控制器
 * @Author:         LOPER7
 * @Email:          loper7@163.com
 */
class DateTimeController : BaseDateTimeController() {
    private var mYearSpinner: NumberPicker? = null
    private var mMonthSpinner: NumberPicker? = null
    private var mDaySpinner: NumberPicker? = null
    private var mHourSpinner: NumberPicker? = null
    private var mMinuteSpinner: NumberPicker? = null
    private var mSecondSpinner: NumberPicker? = null

    private var mYear = 0
    private var mMonth = 0
    private var mDay = 0
    private var mHour = 0
    private var mMinute = 0
    private var mSecond = 0

    private var minMillisecond = 0L
    private var minMonth = 1
    private var minDay = 1
    private var minHour = 0
    private var minMinute = 0
    private var minSecond = 0

    private var maxMillisecond = 0L
    private var maxMonth = 12
    private var maxDay = 31
    private var maxHour = 23
    private var maxMinute = 59
    private var maxSecond = 59

    private var global = DateTimeConfig.GLOBAL_LOCAL

    private var millisecond: Long = 0
    private var mOnDateTimeChangedListener: ((Long) -> Unit)? = null

    private var wrapSelectorWheel = true
    private var wrapSelectorWheelTypes: MutableList<Int>? = null


    override fun bindPicker(type: Int, picker: NumberPicker?): DateTimeController {
        when (type) {
            YEAR -> mYearSpinner = picker
            MONTH -> mMonthSpinner = picker
            DAY -> mDaySpinner = picker
            HOUR -> mHourSpinner = picker
            MIN -> mMinuteSpinner = picker
            SECOND -> mSecondSpinner = picker
        }
        return this
    }

    override fun bindGlobal(global: Int): DateTimeController {
        this.global = global
        return this
    }

    override fun build(): DateTimeController {
        val mDate = Calendar.getInstance()
        mYear = mDate.get(Calendar.YEAR)
        mMonth = mDate.get(Calendar.MONTH) + 1
        mDay = mDate.get(Calendar.DAY_OF_MONTH)
        mHour = mDate.get(Calendar.HOUR_OF_DAY)
        mMinute = mDate.get(Calendar.MINUTE)
        mSecond = mDate.get(Calendar.SECOND)
        millisecond = mDate.timeInMillis

        mYearSpinner?.run {
            maxValue = mYear + 100
            minValue = 1900
            value = mYear
            isFocusable = true
            isFocusableInTouchMode = true
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS //设置NumberPicker不可编辑
            setOnValueChangedListener(mOnYearChangedListener) //注册NumberPicker值变化时的监听事件
        }


        mMonthSpinner?.run {
            maxValue = 12
            minValue = 1
            value = mMonth
            isFocusable = true
            isFocusableInTouchMode = true

            formatter = if (DateTimeConfig.showChina(global))
                DateTimeConfig.formatter //格式化显示数字，个位数前添加0
            else
                DateTimeConfig.globalMonthFormatter

            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener(mOnMonthChangedListener)
        }

        mDaySpinner?.run {
            leapMonth() //判断是否闰年，从而设置2月份的天数
            value = mDay
            isFocusable = true
            isFocusableInTouchMode = true
            formatter = DateTimeConfig.formatter
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener(mOnDayChangedListener)
        }

        mHourSpinner?.run {
            maxValue = 23
            minValue = 0
            isFocusable = true
            isFocusableInTouchMode = true
            value = mHour
            formatter = DateTimeConfig.formatter
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener(mOnHourChangedListener)
        }

        mMinuteSpinner?.run {
            maxValue = 59
            minValue = 0
            isFocusable = true
            isFocusableInTouchMode = true
            value = mMinute
            formatter = DateTimeConfig.formatter
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener(mOnMinuteChangedListener)
        }

        mSecondSpinner?.run {
            maxValue = 59
            minValue = 0
            isFocusable = true
            isFocusableInTouchMode = true
            value = mMinute
            formatter = DateTimeConfig.formatter
            descendantFocusability = NumberPicker.FOCUS_BLOCK_DESCENDANTS
            setOnValueChangedListener(mOnSecondChangedListener)
        }
        return this
    }


    private val mOnYearChangedListener = NumberPicker.OnValueChangeListener { _, _, _ ->
        leapMonth()
        limitMaxAndMin()
        onDateTimeChanged()
    }

    private val mOnMonthChangedListener = NumberPicker.OnValueChangeListener { _, _, _ ->
        leapMonth()
        limitMaxAndMin()
        onDateTimeChanged()
    }

    private val mOnDayChangedListener = NumberPicker.OnValueChangeListener { _, _, _ ->
        limitMaxAndMin()
        onDateTimeChanged()
    }

    private val mOnHourChangedListener = NumberPicker.OnValueChangeListener { _, _, _ ->
        limitMaxAndMin()
        onDateTimeChanged()
    }

    private val mOnMinuteChangedListener = NumberPicker.OnValueChangeListener { _, _, _ ->
        limitMaxAndMin()
        onDateTimeChanged()
    }

    private val mOnSecondChangedListener = NumberPicker.OnValueChangeListener { _, _, _ ->
        onDateTimeChanged()
    }

    /**
     * 同步数据
     */
    private fun syncDateData() {
        mYearSpinner?.apply { mYear = value }
        mMonthSpinner?.apply { mMonth = value }
        mDaySpinner?.apply { mDay = value }
        mHourSpinner?.apply { mHour = value }
        mMinuteSpinner?.apply { mMinute = value }
        mSecondSpinner?.apply { mSecond = value }
    }

    /**
     * 日期发生变化
     */
    private fun onDateTimeChanged() {
        syncDateData()

        val simpleDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date: Date = simpleDateFormat.parse("$mYear-$mMonth-$mDay $mHour:$mMinute:$mSecond")
        millisecond = date.time

        if (mOnDateTimeChangedListener != null) {
            mOnDateTimeChangedListener?.invoke(millisecond)
        }
    }

    /**
     * 判定闰月
     */
    private fun leapMonth() {
        mYearSpinner?.apply { mYear = value }
        mMonthSpinner?.apply { mMonth = value }
        mDaySpinner?.run {
            displayedValues = null
            minValue = 1
            maxValue = getMaxDayInMonth(mYear, mMonth-1)
        }
        if (mYear == mYearSpinner?.minValue && mMonth == mMonthSpinner?.minValue) {
            mDaySpinner?.run {
                minValue = minDay
            }
        }
    }

    /**
     * 设置允许选择的区间
     */
    private fun limitMaxAndMin() {
        syncDateData()
        //设置月份最小值
        mMonthSpinner?.run { minValue = if (mYear == mYearSpinner?.minValue) minMonth else 1 }

        //设置月份最大值
        mMonthSpinner?.run { maxValue = if (mYear == mYearSpinner?.maxValue) maxMonth else 12 }


        /** */ //设置天最小值
        mDaySpinner?.run {
            minValue =
                if (mYear == mYearSpinner?.minValue && mMonth == mMonthSpinner?.minValue) minDay
                else 1
        }


        //设置天最大值
        mDaySpinner?.run {
            maxValue =
                if (mYear == mYearSpinner?.maxValue && mMonth == mMonthSpinner?.maxValue) maxDay
                else getMaxDayInMonth(mYear, mMonth-1)
        }


        /** */ //设置小时最小值
        mHourSpinner?.run {
            minValue =
                if (mYear == mYearSpinner?.minValue && mMonth == mMonthSpinner?.minValue && mDay == mDaySpinner?.minValue) minHour
                else 0
        }


        //设置小时最大值
        mHourSpinner?.run {
            maxValue =
                if (mYear == mYearSpinner?.maxValue && mMonth == mMonthSpinner?.maxValue && mDay == mDaySpinner?.maxValue) maxHour
                else 23
        }


        /** */ //设置分钟最小值
        mMinuteSpinner?.run {
            minValue =
                if (mYear == mYearSpinner?.minValue && mMonth == mMonthSpinner?.minValue && mDay == mDaySpinner?.minValue && mHour == mHourSpinner?.minValue) minMinute
                else 0
        }


        //设置分钟最大值
        mMinuteSpinner?.run {
            maxValue =
                if (mYear == mYearSpinner?.maxValue && mMonth == mMonthSpinner?.maxValue && mDay == mDaySpinner?.maxValue && mHour == mHourSpinner?.maxValue) maxMinute
                else 59
        }


        /** */ //设置秒最小值
        mSecondSpinner?.run {
            minValue =
                if (mYear == mYearSpinner?.minValue && mMonth == mMonthSpinner?.minValue && mDay == mDaySpinner?.minValue && mHour == mHourSpinner?.minValue && mMinute == mMinuteSpinner?.minValue) minSecond
                else 0
        }


        //设置秒最大值
        mSecondSpinner?.run {
            maxValue =
                if (mYear == mYearSpinner?.maxValue && mMonth == mMonthSpinner?.maxValue && mDay == mDaySpinner?.maxValue && mHour == mHourSpinner?.maxValue && mMinute == mMinuteSpinner?.maxValue) maxSecond
                else 59
        }

        setWrapSelectorWheel(wrapSelectorWheelTypes, wrapSelectorWheel)

    }


    override fun setDefaultMillisecond(time: Long) {
        var vTime = time
        if (vTime == 0L) vTime = System.currentTimeMillis()
        if (vTime < minMillisecond) return
        if (maxMillisecond in 1 until vTime) return

        val mCalendar = Calendar.getInstance()
        mCalendar.timeInMillis = vTime
        mYear = mCalendar.get(Calendar.YEAR)
        mMonth = mCalendar.get(Calendar.MONTH) + 1
        mDay = mCalendar.get(Calendar.DAY_OF_MONTH)
        mHour = mCalendar.get(Calendar.HOUR_OF_DAY)
        mMinute = mCalendar.get(Calendar.MINUTE)
        mSecond = mCalendar.get(Calendar.SECOND)

        millisecond = vTime
        mYearSpinner?.value = mYear
        mMonthSpinner?.value = mMonth
        mDaySpinner?.value = mDay
        mHourSpinner?.value = mHour
        mMinuteSpinner?.value = mMinute
        mSecondSpinner?.value = mSecond

        limitMaxAndMin()
        onDateTimeChanged()
    }

    override fun setMinMillisecond(time: Long) {

        if (time == 0L) return
        if (maxMillisecond > 0L && maxMillisecond < time) return
        minMillisecond = time
        val mCalendar = Calendar.getInstance()
        mCalendar.timeInMillis = time
        minMonth = mCalendar.get(Calendar.MONTH) + 1
        minDay = mCalendar.get(Calendar.DAY_OF_MONTH)
        minHour = mCalendar.get(Calendar.HOUR_OF_DAY)
        minMinute = mCalendar.get(Calendar.MINUTE)
        minSecond = mCalendar.get(Calendar.SECOND)
        mYearSpinner?.minValue = mCalendar.get(Calendar.YEAR)



        limitMaxAndMin()
        setWrapSelectorWheel(wrapSelectorWheelTypes, wrapSelectorWheel)
        if (this.millisecond < minMillisecond) setDefaultMillisecond(minMillisecond)
    }

    override fun setMaxMillisecond(time: Long) {
        if (time == 0L) return
        if (minMillisecond > 0L && time < minMillisecond) return
        maxMillisecond = time
        val mCalendar = Calendar.getInstance()
        mCalendar.timeInMillis = time
        maxMonth = mCalendar.get(Calendar.MONTH) + 1
        maxDay = mCalendar.get(Calendar.DAY_OF_MONTH)
        maxHour = mCalendar.get(Calendar.HOUR_OF_DAY)
        maxMinute = mCalendar.get(Calendar.MINUTE)
        maxSecond = mCalendar.get(Calendar.SECOND)

        mYearSpinner?.maxValue = mCalendar.get(Calendar.YEAR)
        limitMaxAndMin()
        setWrapSelectorWheel(wrapSelectorWheelTypes, wrapSelectorWheel)
        if (this.millisecond > maxMillisecond) setDefaultMillisecond(maxMillisecond)
    }


    override fun setWrapSelectorWheel(types: MutableList<Int>?, wrapSelector: Boolean) {
        this.wrapSelectorWheelTypes = types
        this.wrapSelectorWheel = wrapSelector
        if (wrapSelectorWheelTypes == null || wrapSelectorWheelTypes!!.isEmpty()) {
            wrapSelectorWheelTypes = mutableListOf()
            wrapSelectorWheelTypes!!.add(YEAR)
            wrapSelectorWheelTypes!!.add(MONTH)
            wrapSelectorWheelTypes!!.add(DAY)
            wrapSelectorWheelTypes!!.add(HOUR)
            wrapSelectorWheelTypes!!.add(MIN)
            wrapSelectorWheelTypes!!.add(SECOND)
        }

        wrapSelectorWheelTypes!!.apply {
            for (type in this) {
                when (type) {
                    YEAR -> mYearSpinner?.run { wrapSelectorWheel = wrapSelector }
                    MONTH -> mMonthSpinner?.run { wrapSelectorWheel = wrapSelector }
                    DAY -> mDaySpinner?.run { wrapSelectorWheel = wrapSelector }
                    HOUR -> mHourSpinner?.run { wrapSelectorWheel = wrapSelector }
                    MIN -> mMinuteSpinner?.run { wrapSelectorWheel = wrapSelector }
                    SECOND -> mSecondSpinner?.run { wrapSelectorWheel = wrapSelector }
                }
            }
        }
    }


    override fun setOnDateTimeChangedListener(callback: ((Long) -> Unit)?) {
        mOnDateTimeChangedListener = callback
        onDateTimeChanged()
    }

    override fun getMillisecond(): Long {
        return millisecond
    }

}
